﻿using System;
using System.Reflection;
using System.Runtime.CompilerServices;

public static class DelegateFactory
{
    public static LateBoundMethod CreateDelegate(MethodInfo method)
    {
        ParameterInfo[] parameters = method.GetParameters();
        if (parameters.Length == 0)
        {
            return CreateDelegate(method, parameters, typeof(Func<,>), typeof(GC));
        }
        if (parameters.Length == 1)
        {
            return CreateDelegate(method, parameters, typeof(Func<,,>), typeof(GC));
        }
        if (parameters.Length != 2)
        {
            throw new NotImplementedException("Not Implemented Yet.");
        }
        return CreateDelegate(method, parameters, typeof(Func<,,,>), typeof(GC));
    }

    private static LateBoundMethod CreateDelegate(MethodInfo method, ParameterInfo[] parameters, System.Type typeOfDelegate, System.Type typeOfGC)
    {
        System.Type[] typeArguments = new System.Type[parameters.Length + 2];
        for (int i = 0; i < parameters.Length; i++)
        {
            typeArguments[i + 1] = parameters[i].ParameterType;
        }
        typeArguments[0] = method.DeclaringType;
        typeArguments[typeArguments.Length - 1] = method.ReturnParameter.ParameterType;
        object obj2 = Delegate.CreateDelegate(typeOfDelegate.MakeGenericType(typeArguments), null, method);
        object[] objArray1 = new object[] { obj2 };
        return (LateBoundMethod) typeOfGC.MakeGenericType(typeArguments).GetMethod("CreateLateBoundMethod").Invoke(null, objArray1);
    }

    private static class GC<TIn1, TOut>
    {
        public static DelegateFactory.LateBoundMethod CreateLateBoundMethod(object delLoose)
        {
            <CreateLateBoundMethod>c__AnonStorey8A<TIn1, TOut> storeya = new <CreateLateBoundMethod>c__AnonStorey8A<TIn1, TOut> {
                delTyit = (Func<TIn1, TOut>) delLoose
            };
            return new DelegateFactory.LateBoundMethod(storeya.<>m__186);
        }

        [CompilerGenerated]
        private sealed class <CreateLateBoundMethod>c__AnonStorey8A
        {
            internal Func<TIn1, TOut> delTyit;

            internal object <>m__186(object target, object[] args)
            {
                return this.delTyit((TIn1) target);
            }
        }
    }

    private static class GC<TIn1, TIn2, TOut>
    {
        public static DelegateFactory.LateBoundMethod CreateLateBoundMethod(object delLoose)
        {
            <CreateLateBoundMethod>c__AnonStorey8B<TIn1, TIn2, TOut> storeyb = new <CreateLateBoundMethod>c__AnonStorey8B<TIn1, TIn2, TOut> {
                delTyit = (Func<TIn1, TIn2, TOut>) delLoose
            };
            return new DelegateFactory.LateBoundMethod(storeyb.<>m__187);
        }

        [CompilerGenerated]
        private sealed class <CreateLateBoundMethod>c__AnonStorey8B
        {
            internal Func<TIn1, TIn2, TOut> delTyit;

            internal object <>m__187(object target, object[] args)
            {
                return this.delTyit((TIn1) target, (TIn2) args[0]);
            }
        }
    }

    private static class GC<TIn1, TIn2, TIn3, TOut>
    {
        public static DelegateFactory.LateBoundMethod CreateLateBoundMethod(object delLoose)
        {
            <CreateLateBoundMethod>c__AnonStorey8C<TIn1, TIn2, TIn3, TOut> storeyc = new <CreateLateBoundMethod>c__AnonStorey8C<TIn1, TIn2, TIn3, TOut> {
                delTyit = (Func<TIn1, TIn2, TIn3, TOut>) delLoose
            };
            return new DelegateFactory.LateBoundMethod(storeyc.<>m__188);
        }

        [CompilerGenerated]
        private sealed class <CreateLateBoundMethod>c__AnonStorey8C
        {
            internal Func<TIn1, TIn2, TIn3, TOut> delTyit;

            internal object <>m__188(object target, object[] args)
            {
                return this.delTyit((TIn1) target, (TIn2) args[0], (TIn3) args[1]);
            }
        }
    }

    public delegate object LateBoundMethod(object target, object[] arguments);
}

